package com.xh.baselibrary.tts;

import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.text.TextUtils;
import android.util.Log;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Copyright (C), 2022, GDC VR Team
 * Author: GW00239435
 * Date: 2022/4/11
 * Description:
 * History:
 * <author>    <time>     <version>  <desc>
 * GW00239435    2022/4/11      v0.1       FirstVersion
 */
public class TTSByteArrPlay {
    private final static String TAG = TTSByteArrPlay.class.getSimpleName();
    private AudioTrack mAudioTrack = null;
    private final Context mContext;
    private final int mUsage;
    private final int mContentType;
    private final int mSampleRate;
    private final int minBufferSize;//一个采样点16比特-2个字节

    private AudioPlayListener mStateListener;

    private volatile boolean isPlaying = false;

    private final ExecutorService mExecutor;

    private final Map<String, TTSResponderRunnable> runnableMap = new HashMap<>();

    private final ReentrantLock mLock = new ReentrantLock();


    public TTSByteArrPlay(Context context, int usage, int contentType, int sampleRate, ExecutorService executor, AudioPlayListener stateListener) {
        mContext = context;
        mUsage = usage;
        mContentType = contentType;
        mStateListener = stateListener;
        mExecutor = executor;
        mSampleRate = sampleRate;
        minBufferSize = (int)(AudioTrack.getMinBufferSize(mSampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT)) * 2;
    }

    public boolean isPlaying() {
        return isPlaying;
    }


    public void pauseTTS() {
        if (mAudioTrack != null && mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
            mAudioTrack.pause();
        }
    }

    public void continuePlayTTS() {
        if (mAudioTrack != null && mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
            mAudioTrack.play();
        }
    }


    private boolean initAudioTrack() {
        Log.i(TAG, "init AudioTrack,minBufferSize==" + minBufferSize);
        if (mAudioTrack != null && mAudioTrack.getState() == AudioTrack.STATE_INITIALIZED) {
            return true;
        }

        if (mAudioTrack != null) {
            mAudioTrack.release();
            mAudioTrack = null;
        }
        mAudioTrack = new AudioTrack(
                new AudioAttributes.Builder()
                        .setUsage(mUsage)
                        .setContentType(mContentType)
                        .build(),
                new AudioFormat.Builder()
                        .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
                        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                        .setSampleRate(mSampleRate)
                        .build(),
                minBufferSize,
                AudioTrack.MODE_STREAM,
                AudioManager.AUDIO_SESSION_ID_GENERATE);

        if (mAudioTrack.getState() == AudioTrack.STATE_INITIALIZED) {
            return true;
        } else {
            mAudioTrack = null;
            return false;
        }
    }


    private void stopPlay() {
        mLock.lock();
        try {
            Log.i(TAG, "stopPlay");
            if (!isPlaying) {
                return;
            }
            isPlaying = false;
            if (mAudioTrack == null) {
                return;
            }
            if (mAudioTrack.getPlayState() != AudioTrack.STATE_UNINITIALIZED) {
//                mAudioTrack.pause();
                mAudioTrack.stop();
                mAudioTrack.flush();
            }
        } finally {
            mLock.unlock();
        }
    }

    void release() {
        mLock.lock();
        try {
            Log.i(TAG, "releasePlay");
            if (mAudioTrack != null) {
                if (mAudioTrack.getPlayState() != AudioTrack.STATE_UNINITIALIZED) {
//                    mAudioTrack.pause();
                    mAudioTrack.stop();
                    mAudioTrack.flush();
                }
                mAudioTrack.release();
            }
            mAudioTrack = null;
            stopAllResponse();
//            mExecutor.shutdownNow();
        } finally {
            mLock.unlock();
        }
    }


    void addResponseQueue(TTSResponse response) {
        if (response == null) {
            return;
        }
        if (mExecutor == null) {
            return;
        }
        String uuID = response.getUUID();
        mLock.lock();
        try {
            if (runnableMap.containsKey(uuID)) {
                return;
            }
            TTSResponderRunnable runnable = new TTSResponderRunnable(response);
            runnableMap.put(uuID, runnable);
            mExecutor.execute(runnable);
        } finally {
            mLock.unlock();
        }
    }


    void stopAllResponse() {
        mLock.lock();
        try {
            Iterator<Map.Entry<String, TTSResponderRunnable>> it = runnableMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, TTSResponderRunnable> requestEntry = it.next();
                requestEntry.getValue().stopWrite();
                it.remove();
            }
        } finally {
            mLock.unlock();
        }
    }

    void stopPlay(String uuID) {
        if (TextUtils.isEmpty(uuID)) {
            return;
        }
        mLock.lock();
        try {
            TTSResponderRunnable ttsResponderRunnable = runnableMap.remove(uuID);
            if (ttsResponderRunnable != null) {
                ttsResponderRunnable.stopWrite();
            }
        } finally {
            mLock.unlock();
        }
    }


    private class TTSResponderRunnable extends Thread {
        //生成的结果数组
        private final TTSResponse mResponse;
        private FileOutputStream fileOutputStream = null;
        public TTSResponderRunnable(TTSResponse response) {
            super(TTSResponderRunnable.class.getSimpleName());
            mResponse = response;

            try {
                fileOutputStream = new FileOutputStream("sdcard/tts_play.pcm",true);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
        }

        private volatile boolean isStop = false;

        void stopWrite() {
            Log.i(TAG, "stopWrite()----->mResponse=" + mResponse);
            isStop = true;
            mResponse.pcmDeque.clear();
            //防止interrupt()调用后线程不能触发InterruptedException而导致线程一直阻塞在take位置
            TTSResponse.ResponseData data = new TTSResponse.ResponseData(new byte[0]);
            data.isFinish = true;
            mResponse.pcmDeque.add(data);
            this.interrupt();
        }

        @Override
        public void run() {
            Log.i(TAG, "startPlay");
            if (initAudioTrack()) {
                isPlaying = true;
                mAudioTrack.play();
            } else {
                isStop = true;
            }
            if (mStateListener != null) {
                mStateListener.onStartPlay(mResponse);
            }
            while (!isStop) {
                TTSResponse.ResponseData data;
                try {
                    data = mResponse.pcmDeque.take();
                    if (fileOutputStream != null) {
                        try {
                            fileOutputStream.write(data.getBytes());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    writeVoice(data.getBytes());
                    if (data.isFinish()) {
                        break;
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                    isStop = true;
                    Log.i(TAG, "InterruptedException----->" + mResponse.toString());
                    break;
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.flush();
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            stopPlay();
            if (mStateListener != null) {
                if (isStop) {
                    mStateListener.onStoppedPlay(mResponse);
                } else {
                    mStateListener.onFinishPlay(mResponse);
                }
            }
            mLock.lock();
            try {
                runnableMap.remove(mResponse.getUUID());
            } finally {
                mLock.unlock();
            }
        }


        private void writeVoice(byte[] voice) {
            if (voice == null || voice.length == 0) {
                return;
            }
//            Log.d(TAG, "WriteVoice，voice.length==" + voice.length);
            final int L = voice.length;
            final int bufferSize = (int) (minBufferSize);
//            Log.i(TAG, "bufferSize  ==" + bufferSize);
//            Log.i(TAG, "voice.size ==" + voice.length);
            if (L > bufferSize) {
                final int times = L / bufferSize;

                int dstPos = 0;
                for (int i = 0; i <= times; i++) {
                    if (isStop) {
                        return;
                    }
                    int length = bufferSize;
                    if (dstPos + bufferSize >= voice.length) {
                        length = voice.length - dstPos;
                    }
                    byte[] bytes = new byte[length];
                    // Log.i(TAG, "WriteVoice，length==" + length);
                    System.arraycopy(voice, dstPos, bytes, 0, length);
                    if (mAudioTrack != null && mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
//                        long start1 = System.currentTimeMillis();
                        int bytesWritten = mAudioTrack.write(bytes, 0, length);
//                        long end1 = System.currentTimeMillis();
//                        Log.i(TAG, "Decoder-write else ," + bytesWritten + "," + (end1 - start1));
                    } else {
                        break;
                    }
                    dstPos += length;
                }
            } else {
                if (mAudioTrack != null && mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
//                    long start1 = System.currentTimeMillis();
                    int bytesWritten = mAudioTrack.write(voice, 0, voice.length);

//                    long end1 = System.currentTimeMillis();
//                    Log.i(TAG, "Decoder-write else ," + bytesWritten + "," + (end1 - start1));
                }
            }
        }
    }
    public interface AudioPlayListener {
        void onStartPlay(TTSResponse response);

        void onFinishPlay(TTSResponse response);

        void onStoppedPlay(TTSResponse response);
    }

}
